/*
 *  testClassTransactionLogBuffer.cpp
 *  kangmodb
 *
 *  Created by 강모 김 on 11. 4. 25..
 *  Copyright 2011 강모소프트. All rights reserved.
 *
 */


#include "gtest/gtest.h"

#include "kangmodb.h"
#include "testCommon.h"

/** @brief Test stgTransactionLogBuffer class 
 */
class ClassTransactionLogBufferTest : public testing::Test {
protected:  // You should make the members protected s.t. they can be
	// accessed from sub-classes.
	
	// virtual void SetUp() will be called before each test is run.  You
	// should define it if you need to initialize the varaibles.
	// Otherwise, this can be skipped.
	virtual void SetUp() {
	}
	
	// virtual void TearDown() will be called after each test is run.
	// You should define it if there is cleanup work to do.  Otherwise,
	// you don't have to provide it.
	//
	virtual void TearDown() {
	}
protected:
};


TEST_F(ClassTransactionLogBufferTest, DISABLED_Basic) {
	const void *     savepoint1Record;
	const void *     savepoint2Record;
	const void *     logRecord;
	int              logRecordLength;
	stgTableId       tableId;
	stgSavepointId   savepointId;
	const stgTableId TABLE_ID=1;
	stgTransactionLogBuffer txLogBuf;
	stgKey  key;
	stgData data;
	
	// Write logs
	{
		EXPECT_TRUE( txLogBuf.empty() );
		EXPECT_TRUE( txLogBuf.writeInsertLog(TABLE_ID, stgKey("key1"), stgData("data1", 5)) == 0 ); 
		EXPECT_FALSE( txLogBuf.empty() );
		EXPECT_TRUE( txLogBuf.writeSavepointLog(TABLE_ID, 1 ) == 0 ); 
		EXPECT_TRUE( txLogBuf.writeUpdateLog(TABLE_ID, stgKey("key1"), stgData("data2", 5)) == 0 ); 
		EXPECT_TRUE( txLogBuf.writeSavepointLog(TABLE_ID, 2 ) == 0 ); 
		EXPECT_TRUE( txLogBuf.writeDeleteLog(TABLE_ID, stgKey("key1")) == 0 ); 
		EXPECT_FALSE( txLogBuf.empty() );
	}

	// Read logs
    {
		// Start a new log iteration
		EXPECT_TRUE( txLogBuf.initLogRecordReverseIteration() == 0 );
	
		// The log for delete key1
		EXPECT_TRUE( txLogBuf.reverseIterateLogRecord( &logRecord, &logRecordLength ) == 0 );
		EXPECT_TRUE( logRecord != NULL && logRecordLength != 0 );
		EXPECT_TRUE( stgLogFormatter::isDeleteLog( logRecord ) );
		(void)stgLogFormatter::readDeleteLog( logRecord, &tableId, &key);
		EXPECT_TRUE( key.compare(stgKey("key1")) == 0 );

		// The log for savepoint 2
		EXPECT_TRUE( txLogBuf.reverseIterateLogRecord( &savepoint2Record, &logRecordLength ) == 0 );
		EXPECT_TRUE( stgLogFormatter::isSavepointLog( savepoint2Record ) );
		(void)stgLogFormatter::readSavepointLog( savepoint2Record, &tableId, &savepointId);
		EXPECT_EQ( tableId, TABLE_ID );
		EXPECT_EQ( savepointId, 2);
	
		// The log for update (key1, data2)
		EXPECT_TRUE( txLogBuf.reverseIterateLogRecord( &logRecord, &logRecordLength ) == 0 );
		EXPECT_TRUE( stgLogFormatter::isUpdateLog( logRecord ) );
		(void)stgLogFormatter::readUpdateLog( logRecord, &tableId, &key, &data);
		EXPECT_TRUE( key.compare(stgKey("key1")) == 0 );
		EXPECT_TRUE( data.compare(stgData("data2", 5)) == 0 );

		
		// The log for savepoint 1
		EXPECT_TRUE( txLogBuf.reverseIterateLogRecord( &savepoint1Record, &logRecordLength ) == 0 );
		EXPECT_TRUE( stgLogFormatter::isSavepointLog( savepoint1Record ) );
		(void)stgLogFormatter::readSavepointLog( savepoint1Record, &tableId, &savepointId);
		EXPECT_EQ( tableId, TABLE_ID );
		EXPECT_EQ( savepointId, 1);
	
		// The log for insert (key1, data1)
		EXPECT_TRUE( txLogBuf.reverseIterateLogRecord( &logRecord, &logRecordLength ) == 0 );
		EXPECT_TRUE( stgLogFormatter::isInsertLog( logRecord ) );
		(void)stgLogFormatter::readInsertLog( logRecord, &tableId, &key, &data);
		EXPECT_TRUE( key.compare(stgKey("key1")) == 0 );
		EXPECT_TRUE( data.compare(stgData("data1", 5)) == 0 );

		// End of log records.
		EXPECT_TRUE( txLogBuf.reverseIterateLogRecord( &logRecord, &logRecordLength ) == 0 );
		EXPECT_TRUE( logRecord == NULL && logRecordLength == 0 );
    }

	// Truncate up to the savepoint 2, check logs
	{
		EXPECT_TRUE( txLogBuf.truncate(savepoint2Record) == 0 );
	
		// Start a new log iteration
		EXPECT_TRUE( txLogBuf.initLogRecordReverseIteration() == 0 );
	
		// The log for update (key1, data2)
		EXPECT_TRUE( txLogBuf.reverseIterateLogRecord( &logRecord, &logRecordLength ) == 0 );
		EXPECT_TRUE( stgLogFormatter::isUpdateLog( logRecord ) );
		(void)stgLogFormatter::readUpdateLog( logRecord, &tableId, &key, &data);
		EXPECT_TRUE( key.compare(stgKey("key1")) == 0 );
		EXPECT_TRUE( data.compare(stgData("data2", 5)) == 0 );

		
		// The log for savepoint 1
		EXPECT_TRUE( txLogBuf.reverseIterateLogRecord( &savepoint1Record, &logRecordLength ) == 0 );
		EXPECT_TRUE( stgLogFormatter::isSavepointLog( savepoint1Record ) );
		(void)stgLogFormatter::readSavepointLog( savepoint1Record, &tableId, &savepointId);
		EXPECT_EQ( tableId, TABLE_ID );
		EXPECT_EQ( savepointId, 1);
	
		// The log for insert (key1, data1)
		EXPECT_TRUE( txLogBuf.reverseIterateLogRecord( &logRecord, &logRecordLength ) == 0 );
		EXPECT_TRUE( stgLogFormatter::isInsertLog( logRecord ) );
		(void)stgLogFormatter::readInsertLog( logRecord, &tableId, &key, &data);
		EXPECT_TRUE( key.compare(stgKey("key1")) == 0 );
		EXPECT_TRUE( data.compare(stgData("data1", 5)) == 0 );

		// End of log records.
		EXPECT_TRUE( txLogBuf.reverseIterateLogRecord( &logRecord, &logRecordLength ) == 0 );
		EXPECT_TRUE( logRecord == NULL && logRecordLength == 0 );
	}

	// Truncate up to the savepoint 1, check logs
	{
		EXPECT_TRUE( txLogBuf.truncate(savepoint1Record) == 0 );
	
		// Start a new log iteration
		EXPECT_TRUE( txLogBuf.initLogRecordReverseIteration() == 0 );
	
		// The log for insert (key1, data1)
		EXPECT_TRUE( txLogBuf.reverseIterateLogRecord( &logRecord, &logRecordLength ) == 0 );
		EXPECT_TRUE( stgLogFormatter::isInsertLog( logRecord ) );
		(void)stgLogFormatter::readInsertLog( logRecord, &tableId, &key, &data);
		EXPECT_TRUE( key.compare(stgKey("key1")) == 0 );
		EXPECT_TRUE( data.compare(stgData("data1", 5)) == 0 );

		// End of log records.
		EXPECT_TRUE( txLogBuf.reverseIterateLogRecord( &logRecord, &logRecordLength ) == 0 );
		EXPECT_TRUE( logRecord == NULL && logRecordLength == 0 );
	}
	
	// Truncate all records in the transaction log buffer, make sure there is no log record.
	{
		EXPECT_TRUE( txLogBuf.truncate(NULL) == 0 );
	
		// Start a new log iteration
		EXPECT_TRUE( txLogBuf.initLogRecordReverseIteration() == 0 );

		// End of log records.
		EXPECT_TRUE( txLogBuf.reverseIterateLogRecord( &logRecord, &logRecordLength ) == 0 );
		EXPECT_TRUE( logRecord == NULL && logRecordLength == 0 );
	}
}